# coding=utf8

import Connection as Connection
import EblobExecption
import re


class Table:
    def __init__(self):
        self.table_name = self.__class__.__name__
        self.row_key = ''

    '''当前情况下会导致死循环
            在存入操作开始之前先判断是否合法可以防止脏数据的产生'''
    def new_save(self, ignore=False):
        if self.row_key == '':
            raise EblobExecption.NoRowKeyException('the row key has not been set, the find could not work')
        muputs = dict()
        client = Connection.Connection()
        if not client.is_existed(self.table_name, self.row_key):
            for ele in dir(self):
                element = getattr(self, ele)

                # 可以判断是否是Cell类型
                if isinstance(element, Table.Cell):
                    # 将对象中的元素提取出来
                    muputs[element.family_column()+':'+ele] = element.value()
                # 判断是否是关系Cell
                if isinstance(element, Table.FixCell):
                    obj = element.value()
                    if isinstance(obj, Table):
                        # 将关系对象写入表
                        obj.new_save(True)
                    # 将二者关系写入关系表
                    fix_muputs = dict()
                    fix_muputs[str(self.__class__.__name__ + ':' + self.__class__.__name__
                                   + '_row_key').lower()] = self.row_key
                    fix_muputs[str(element.table_name() + ':' + element.table_name()
                                                          + '_row_key').lower()] = obj.row_key
                    client.connection_save(self.__class__.__name__ + element.table_name(),
                                           self.row_key + '-' + obj.row_key, fix_muputs)
            # 等待所有的都存入了才会执行这里的存入
            client.connection_save(self.table_name, self.row_key, muputs)
        else:
            if ignore:
                return
            else:
                raise EblobExecption.RowExistException('the row key data is existed')

    def new_update(self):
        if self.row_key == '':
            raise EblobExecption.NoRowKeyException('the row key has not been set, the find could not work')
        muputs = dict()
        client = Connection.Connection()
        if client.is_existed(self.table_name, self.row_key):
            for ele in dir(self):
                element = getattr(self, ele)
                if isinstance(element, Table.Cell):
                    muputs[element.family_column() + ':' + ele] = element.value()
                if isinstance(element, Table.FixCell):
                    obj = element.value()
                    if isinstance(obj, Table):
                        if client.is_existed(obj.table_name, obj.row_key):
                            fix_muputs = dict()
                            fix_muputs[str(self.__class__.__name__ + ':' + self.__class__.__name__
                                           + '_row_key').lower()] = self.row_key
                            fix_muputs[str(element.table_name() + ':' + element.table_name()
                                           + '_row_key').lower()] = obj.row_key
                            client.connection_save(self.__class__.__name__ + element.table_name(),
                                                   self.row_key + '-' + obj.row_key, fix_muputs, True)
                        else:
                            raise EblobExecption.RowIsNotExistException(
                                'the row is not existed, the update could not work')
            client.connection_update(self.table_name, self.row_key, muputs)
        else:
            raise EblobExecption.RowIsNotExistException('the row is not existed, the update could not work')

    def new_find(self, row_key_like, start_row_key, counts):
        client = Connection.Connection()
        result_list = client.connection_find(self.table_name, row_key_like, start_row_key, counts)
        for every_result in result_list:
            for element_name in dir(self):
                element = getattr(self, element_name)
                if isinstance(element, Table.FixCell):
                    sub_result_list = client.connection_find(self.__class__.__name__ + element.table_name(),
                                                             self.row_key + '-.*', '0', 10)
                    every_result[str(self.table_name + ':' + element_name).lower()] = sub_result_list
        return result_list

    def new_get(self):
        if self.row_key == '':
            raise EblobExecption.NoRowKeyException('the row key has not been set, the find could not work')
        client = Connection.Connection()
        result = client.connection_get(self.table_name, self.row_key)
        for element_name in dir(self):
            element = getattr(self, element_name)
            if isinstance(element, Table.FixCell):
                sub_result_list = client.connection_find(self.__class__.__name__ + element.table_name(),
                                                         self.row_key + '-.*', '0', 10)
                result[str(self.table_name + ':' + element_name).lower()] = sub_result_list
        return result

    ''' 删除操作还需要修改，如果是OneToMany，OneToOne需要讲target表中的数据也一并删除'''
    def new_delete(self):
        if self.row_key == '':
            raise EblobExecption.NoRowKeyException('the row key has not been set, the find could not work')
        client = Connection.Connection()
        all_table_names = client.get_tables()
        target_pattern = re.compile(r'\S+'+self.table_name)
        source_pattern = re.compile(self.table_name+r'\S+')
        is_delete = True
        fix_table_names = list()
        ''' 这里是先判断当前表是否为target表如果为target表，并且有外部引用这条数据，则不能删除，
            如果是源表，则把相应的关联表中的数据也删除'''
        for table_name in all_table_names:
            if target_pattern.match(table_name):
                if client.is_existed(table_name, '\S*-' + self.row_key, True):
                    is_delete = False
            elif source_pattern.match(table_name):
                fix_table_names.append(table_name)
        if is_delete:
            if len(fix_table_names) != 0:
                # 循环删除
                for table in fix_table_names:
                    result_list = client.connection_find(table, self.row_key + '-\S*', '0', 214748)
                    for result in result_list:
                        client.connection_delete(table, result['row_key'])
            client.connection_delete(self.table_name, self.row_key)
        else:
            raise EblobExecption.RowOutSideException("the row is outside, other table's have it")

    def new_delete_fix(self, target_table_name, target_row_key):
        client = Connection.Connection()
        client.connection_delete(self.table_name + target_table_name, target_row_key)

    def set_row_key(self, row_key):
        self.row_key = row_key

    def get_row_key(self):
        return self.row_key

    '''Cell用于保存Cell的信息，其中有列名和值'''

    class Cell(object):
        def __init__(self, family_column):
            self._family_column = family_column
            self._value = ''

        def set_column_name(self, family_column):
            self._family_column = family_column

        def set_value(self, value):
            self._value = value

        def family_column(self):
            return self._family_column

        def value(self):
            return self._value

    '''关系型Cell用于存储表和表之间的关系（基类）'''

    class FixCell(object):
        def __init__(self, table_name):
            self._table_name = table_name
            self._value = ''

        '''保存对象时需要添加对象合法性判断'''

        def set_value(self, value):
            self._value = value

        def set_table_name(self, table_name):
            self._table_name = table_name

        def value(self):
            return self._value

        def table_name(self):
            return self._table_name

    '''ManyToManyCell用于保存表多对多的关系'''

    class ManyToManyCell(FixCell):
        def __init__(self, table_name):
            Table.FixCell.__init__(self, table_name)

    '''OneToManyCell用于保存表一对多的关系（'''

    class OneToManyCell(FixCell):
        def __init__(self, table_name):
            Table.FixCell.__init__(self, table_name)

    '''OneToOneCell用于保存表一对一的映射关系'''

    class OneToOneCell(FixCell):
        def __init__(self, table_name):
            Table.FixCell.__init__(self, table_name)
